//      desktop.c
//      
//      Copyright 2011 DJ Shaji <djshaji@gmail.com>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.


#include "desktop.h"

void desktop_init ( void )
{
	Desktop * d = g_slice_new ( Desktop ) ;
	
	d -> hand = gdk_cursor_new ( GDK_HAND2 ) ;
	d -> busy = gdk_cursor_new ( GDK_WATCH ) ;
	
	d -> ptr = gdk_cursor_new ( GDK_LEFT_PTR ) ;
	
	d -> window = gtk_window_new ( GTK_WINDOW_TOPLEVEL ) ;
	d -> lt = gtk_layout_new ( null, null ) ;
	
	gtk_window_resize ( d -> window, gdk_screen_width (), gdk_screen_height ()) ;
	gtk_container_add ( d -> window, d -> lt ) ;
	
	gtk_window_set_type_hint ( d -> window, GDK_WINDOW_TYPE_HINT_DESKTOP ) ;
	
	GdkColor color ;
	color.red = 0 * 257 ;
	
	color.green = 130 * 257 ;
	color.blue = 123 * 257 ;
	
	gint x = 0 ;
	for ( x = GTK_STATE_NORMAL ; x < GTK_STATE_INSENSITIVE ; x ++ )
		gtk_widget_modify_bg ( d -> lt, x, & color ) ;
	
	GtkLabel * version = gtk_label_new ( null ) ;
	gtk_label_set_markup ( version, "<span size=\"small\" color=\"white\"><b>April build 799g</b></span>" ) ;
	
	GtkRequisition qu ;
	gtk_widget_size_request ( version, & qu ) ;
	
	gtk_layout_put ( d -> lt, version, gdk_screen_width () - qu.width - 10, gdk_screen_height () - 30 - qu.height ) ;
	gtk_widget_show ( version ) ;
	
	gtk_widget_show_all ( d -> window ) ;
	april_update_gui () ;
	
	gdk_window_set_cursor ( gtk_widget_get_parent_window ( d -> lt ), d -> busy ) ;
	april_update_gui () ;
	
	d -> wallpaper = gtk_image_new () ;
	gtk_layout_put ( d -> lt, d -> wallpaper, 0, 0 ) ;
	
	d -> store = gtk_list_store_new ( 5, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, GTK_TYPE_WIDGET, G_TYPE_POINTER ) ;
	desktop_load_icons ( d ) ;
	
	//gtk_image_set_from_file ( d -> wallpaper, "desktop/wallpaper.jpg" ) ;
	g_signal_connect_after ( d -> lt, "button-press-event", desktop_show_menu, d ) ;
	
	gdk_beep () ;
	
	gdk_window_set_cursor ( gtk_widget_get_parent_window ( d -> lt ), d -> ptr ) ;
	gtk_widget_show_all ( d -> window ) ;
}

GtkMenu * desktop_create_menu ( Desktop * d )
{
	GtkMenu * menu = gtk_menu_new () ;
	GtkMenuItem * active_desktop = gtk_menu_item_new_with_label ( "Active Desktop" ),
				* arrange_icons = gtk_menu_item_new_with_label ( "Arrange Icons" ),
				* line_up_icons = gtk_menu_item_new_with_label ( "Line Up Icons" ),
				* refresh = gtk_menu_item_new_with_label ( "Refresh" ),
				* paste = gtk_menu_item_new_with_label ( "Paste" ),
				* paste_shortcut = gtk_menu_item_new_with_label ( "Paste Shortcut" ),
				* undo_copy = gtk_menu_item_new_with_label ( "Undo Copy" ),
				* new = gtk_menu_item_new_with_label ( "New" ),
				* properties = gtk_menu_item_new_with_label ( "Properties" ) ;
	
	GtkMenu * active_menu = gtk_menu_new () ;
	GtkMenuItem * a = gtk_check_menu_item_new_with_label ( "Show icons on desktop" ) ;
	
	gtk_menu_shell_append ( active_menu, a ) ;
	gtk_menu_item_set_submenu ( active_desktop, active_menu ) ;
	
	gtk_check_menu_item_set_active ( a, d -> icons_visible ) ;
	
	g_signal_connect ( a, "activate", desktop_toggle_icons, d ) ;
	g_signal_connect ( refresh, "activate", desktop_refresh, null ) ;
	
	g_signal_connect_swapped ( arrange_icons, "activate", desktop_arrange_icons, d ) ;
	g_signal_connect_swapped ( line_up_icons, "activate", desktop_line_up_icons, d ) ;
	
	g_signal_connect_swapped ( paste, "activate", desktop_paste_from_clipboard, d ) ;
	g_signal_connect_swapped ( paste_shortcut, "activate", desktop_paste_shortcut, d ) ;

	g_signal_connect_swapped ( undo_copy, "activate", desktop_delete_from_clipboard, d ) ;

	GtkMenu * new_menu = gtk_menu_new () ;
	GtkMenuItem * new_file = gtk_menu_item_new_with_label ( "Empty file" ),
				* new_folder = gtk_menu_item_new_with_label ( "New Folder" ) ;
	
	gtk_menu_shell_append ( new_menu, new_folder ) ;
	gtk_menu_shell_append ( new_menu, gtk_separator_menu_item_new ()) ;
	
	gtk_menu_shell_append ( new_menu, new_file ) ;
	gtk_menu_item_set_submenu ( new, new_menu ) ;
	
	g_signal_connect_swapped ( new_file, "activate", desktop_new_file, d ) ;
	g_signal_connect_swapped ( new_folder, "activate", desktop_new_folder, d ) ;

	g_signal_connect_swapped ( properties, "activate", desktop_properties, d ) ;

	gtk_menu_shell_append ( menu, active_desktop ) ;
	gtk_menu_shell_append ( menu, gtk_separator_menu_item_new ()) ;
	
	gtk_menu_shell_append ( menu, arrange_icons ) ;
	gtk_menu_shell_append ( menu, line_up_icons ) ;
	
	gtk_menu_shell_append ( menu, gtk_separator_menu_item_new ()) ;
	gtk_menu_shell_append ( menu, refresh ) ;
	
	gtk_menu_shell_append ( menu, gtk_separator_menu_item_new ()) ;
	
	gtk_menu_shell_append ( menu, paste ) ;
	gtk_menu_shell_append ( menu, paste_shortcut ) ;
	
	gtk_menu_shell_append ( menu, undo_copy ) ;
	gtk_menu_shell_append ( menu, gtk_separator_menu_item_new ()) ;
	
	gtk_menu_shell_append ( menu, new ) ;
	gtk_menu_shell_append ( menu, gtk_separator_menu_item_new ()) ;
	
	gtk_menu_shell_append ( menu, properties ) ;
	
	gtk_widget_show_all ( menu ) ;
	return menu ;
}


gboolean desktop_show_menu ( GtkWidget * widget, GdkEventButton * event, Desktop * d )
{
	if ( event -> button != 3 )
		return false ;
	
	GtkMenu * menu = desktop_create_menu ( d ) ;
	g_signal_connect ( menu, "selection-done", gtk_widget_destroy, null ) ;
	
	gtk_menu_popup ( menu, null, null, null, null, 3, gtk_get_current_event_time ()) ;
	return true ;
}

void desktop_load_icons ( Desktop * d )
{
	gchar * desktop = g_build_filename ( g_get_home_dir (), "Desktop", null ) ;
	GError * error = null ;
	
	GDir * dir = g_dir_open ( desktop, 0, & error ) ;
	if ( error )
	{
		g_warning ( error -> message ) ;
		g_free ( desktop ) ;
		
		return ;
	}
	
	gint x = 50, y = 0 ;
	
	gchar * name = g_dir_read_name ( dir ) ;
	while ( name )
	{
		gchar * full_name = g_build_filename ( desktop, name, null ) ;
		GdkPixbuf * p = fm_get_icon ( full_name ) ;
		
		GtkVBox * icon = gtk_vbox_new ( no, 2 ) ;
		GtkImage * image = gtk_image_new_from_pixbuf ( p ) ;
		
		gchar * display_name = _desktop_icon_name_mod ( name ) ;
		
		GtkLabel * label = gtk_label_new ( null ) ;
		gchar * markup = g_markup_printf_escaped ( "<span color=\"white\">%s</span>", display_name ) ;
		
		g_free ( display_name ) ;
		
		gtk_label_set_markup ( label, markup ) ;
		g_free ( markup ) ;
		
		gtk_label_set_line_wrap ( label, true ) ;
		gtk_label_set_justify ( label, GTK_JUSTIFY_CENTER ) ;
		
		//gtk_label_set_ellipsize ( label, PANGO_ELLIPSIZE_END ) ;
		
		//gtk_label_set_line_wrap_mode ( label, GTK_WRAP_WORD_CHAR ) ;
		
		gtk_box_pack_start ( icon, image, no, no, 0 ) ;
		gtk_box_pack_start ( icon, label, no, no, 2 ) ;
		
		gtk_widget_set_tooltip_text ( icon, name ) ;
		
		GtkTreeIter iter ;
		gtk_list_store_append ( d -> store, & iter ) ;
		
		GtkEventBox * e = gtk_event_box_new () ;
		gtk_container_add ( e, icon ) ;
		
		DesktopIcon * c = desktop_icon_new ( d ) ;
		c -> store = d -> store ;
		
		c -> e = e ;
		c -> image = image ;
		
		c -> label = label ;
		c -> path = full_name ;
		
		c -> iter = gtk_tree_iter_copy ( & iter ) ;

		g_signal_connect_swapped ( e, "enter-notify-event", _desktop_icon_pointer_change, c ) ;
		g_signal_connect_swapped ( e, "leave-notify-event", _desktop_icon_pointer_reset, c ) ;

		c -> x = x ;
		c -> y = y ;
		
		g_signal_connect ( e, "button-press-event", desktop_icon_activated, c ) ;
		gtk_layout_put ( d -> lt, e, x, y ) ;
		
		gtk_list_store_set ( d -> store, & iter, 0, p, 1, name, 2, full_name, 3, e, 4, c, -1 ) ;
		gtk_event_box_set_visible_window ( e, no ) ;
		
		g_object_unref ( p ) ;
		///g_free ( full_name ) ;
		
		d -> icons_x = x ;
		d -> icons_y = y ;
		
		y = y + 100 ;
		
		
		if ( y > gdk_screen_height () - 50 )
		{
			x = x + 100 ;
			y = 0 ;
		}
		
		gtk_widget_show_all ( icon ) ;
		name = g_dir_read_name ( dir ) ;
	}
	
	g_dir_close ( dir ) ;
	
	GError * err = null ;
	
	d -> desktop = g_file_new_for_path ( desktop ) ;
	d -> file_monitor = g_file_monitor ( d -> desktop, G_FILE_MONITOR_WATCH_MOUNTS, null, & err ) ;
	
	if ( err )
		g_warning ( err -> message ) ;
	else
		g_signal_connect ( d -> file_monitor, "changed", desktop_changed, d ) ;
	
	g_free ( desktop ) ;
	d -> icons_visible = true ;
}

gchar * _desktop_icon_name_mod ( gchar * name )
{
	gint i = 0, len = strlen ( name ), counter = 0 ;
	GString * s = g_string_new ( null ) ;
	
	for ( i = 0 ; i < len ; i ++ )
	{
		if ( i > 20 )
		{
			g_string_append_printf ( s, "..." ) ;
			break ;
		}
		
		g_string_append_c ( s, name [i] ) ;
		
		if ( counter < 10 )
			counter ++ ;
		else
		{
			g_string_append_c ( s, '\n' ) ;
			counter = 0 ;
		}
	}
	
	return g_string_free ( s, false ) ;
}	

gboolean desktop_icon_activated ( GtkWidget * widget, GdkEventButton * event, DesktopIcon * icon )
{
	if ( event -> button == 1 )
	{
		mime_handler ( null, icon -> path ) ;
		return true ;
	}
	
	else if ( event -> button == 3 )
	{
		GtkMenu * menu = desktop_create_menu_file ( icon ) ;
		g_signal_connect ( menu, "selection-done", gtk_widget_destroy, null ) ;
		
		gtk_menu_popup ( menu, null, null, null, null, 3, gtk_get_current_event_time ()) ;
		return true;		
	}
	
	return false ;
}

DesktopIcon * desktop_icon_new ( Desktop * d )
{
	DesktopIcon * icon = g_slice_new ( DesktopIcon ) ;
	icon -> desktop = d ;
}

void desktop_icon_destroy ( DesktopIcon * icon )
{
	g_free ( icon -> path ) ;
	gtk_tree_iter_free ( icon -> iter ) ;

	gtk_widget_destroy ( icon -> e ) ;
	g_slice_free ( DesktopIcon, icon ) ;
}

GtkMenu * desktop_create_menu_file ( DesktopIcon * icon )
{
	GtkMenu * menu = gtk_menu_new () ;
	GtkMenuItem * open = gtk_menu_item_new_with_label ( "Open" ),
				* open_with = gtk_menu_item_new_with_label ( "Open with..." ),
//				* explore = gtk_menu_item_new_with_label ( "Explore" ),
				* remove_from_desktop = gtk_menu_item_new_with_label ( "Remove from Desktop" ),
//				* create_shortcut = gtk_menu_item_new_with_label ( "Create Shortcut" ),
				* rename = gtk_menu_item_new_with_label ( "Rename" ),
				* properties = gtk_menu_item_new_with_label ( "Properties" ) ;
	
	g_signal_connect_swapped ( open, "activate", desktop_open, icon -> path ) ;
	g_signal_connect_swapped ( open_with, "activate", desktop_open_with, icon ) ;
	
	g_signal_connect_swapped ( remove_from_desktop, "activate", desktop_icon_delete, icon ) ;
	g_signal_connect_swapped ( rename, "activate", desktop_icon_rename, icon ) ;
	
	g_signal_connect_swapped ( properties, "activate", desktop_icon_properties, icon ) ;

	gtk_menu_shell_append ( menu, open ) ;
	gtk_menu_shell_append ( menu, open_with ) ;
	
	gtk_menu_shell_append ( menu, gtk_separator_menu_item_new ()) ;
	gtk_menu_shell_append ( menu, remove_from_desktop ) ;
	
	//gtk_menu_shell_append ( menu, gtk_separator_menu_item_new ()) ;
	
	//gtk_menu_shell_append ( menu, create_shortcut ) ;
	gtk_menu_shell_append ( menu, rename ) ;
	
	gtk_menu_shell_append ( menu, gtk_separator_menu_item_new ()) ;
	gtk_menu_shell_append ( menu, properties ) ;
	
	gtk_widget_show_all ( menu ) ;
	return menu ;
}

void desktop_open ( gchar * filename )
{
	mime_handler ( null, filename ) ;
}

void desktop_icon_delete ( DesktopIcon * icon )
{
	gtk_list_store_remove ( icon -> desktop -> store, icon -> iter ) ;
	desktop_icon_destroy ( icon ) ;
}

vodi desktop_icon_rename ( DesktopIcon * icon )
{
	GtkDialog * dialog = gtk_dialog_new_with_buttons ( "Rename icon",
														null,
														GTK_DIALOG_MODAL,
														"Cancel",
														0,
														"Rename",
														1,
														null ) ;
	
	GtkEntry * entry = gtk_entry_new () ;
	gtk_box_pack_start ( dialog -> vbox, entry, no, no, 2 ) ;
	
	gchar * basename = g_path_get_basename ( icon -> path ) ;
	gtk_widget_set_size_request ( entry, 400, 20 ) ;
	
	gtk_entry_set_text ( entry, basename ) ;
	gtk_widget_show_all ( dialog ) ;

	if ( gtk_dialog_run ( dialog ))
	{
		gchar * markup = g_markup_printf_escaped ( "<span color=\"white\">%s</span>", gtk_entry_get_text ( entry )) ;
		gtk_label_set_markup ( icon -> label, markup ) ;
		
		g_free ( markup ) ;
	}
	
	g_free ( basename ) ;
	gtk_widget_destroy ( dialog ) ;
}

vodi desktop_icon_properties ( DesktopIcon * icon )
{
	GFile * file = g_file_new_for_path ( icon -> path ) ;
	GError * error = null ;
	
	GFileInfo * info = g_file_query_info ( file, "*", G_FILE_QUERY_INFO_NONE, null, & error ) ;
	if ( error )
	{
		g_warning ( error -> message ) ;
		g_object_unref ( file ) ;
		
		g_object_unref ( info ) ;
		return ;
	}
	
	gchar ** attributes = g_file_info_list_attributes ( info, null ) ;
	gint i = 0 ;
	
	GString * s = g_string_new ( null ) ;
	
	while ( attributes [i] != null )
	{
		gchar * a = g_file_info_get_attribute_as_string ( info, attributes [i] ) ;
		g_string_append_printf ( s, "%s: %s\n", attributes [i], a ) ;
		
		g_free ( a ) ;
		i ++ ;
	}
	
	g_strfreev ( attributes ) ;
	gchar * basename = g_path_get_basename ( icon -> path ) ;
	
	prompt_detailed_info ( basename, s -> str ) ;
	g_string_free ( s, true ) ;
	
	g_object_unref ( file ) ;
	g_object_unref ( info ) ;
	
	g_free ( basename ) ;
}	
	
void desktop_open_with ( DesktopIcon * icon )
{
	GtkDialog * dialog = gtk_dialog_new_with_buttons ( "Open with",
														null,
														GTK_DIALOG_MODAL,
														"Cancel",
														0,
														null ) ;
	GtkButton * open_with = gtk_dialog_add_button ( dialog, "Open with", 1 ) ;
	
	GtkCellView * view = gtk_tree_view_new () ;
	GtkTreeModel * store = _open_with_fill_store () ;
	
	GtkScrolledWindow * sw = gtk_scrolled_window_new ( null, null ) ;
	gtk_scrolled_window_set_policy ( sw, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ) ;
	
	gtk_tree_view_set_model ( view, store ) ;
	
	GtkCellRenderer * renderer = gtk_cell_renderer_text_new () ;
	GtkTreeViewColumn * col = gtk_tree_view_column_new_with_attributes ( "Programs",
									renderer,
									"text",
									0,
									null ) ;
	
	g_signal_connect_swapped ( view, "row-activated", gtk_button_clicked, open_with ) ;
	gtk_tree_view_append_column ( view, col ) ;
	
	GtkLabel * l = gtk_label_new ( "Choose program to open the files with:" ) ;
	gtk_label_set_line_wrap ( l, true ) ;
	
	GtkEntry * entry = gtk_entry_new () ;
	GtkCheckButton * always = gtk_check_button_new_with_label ( "Always use this program" ),
					* terminal = gtk_check_button_new_with_label ( "Run in terminal" ) ;
	
	GtkWidget * box = gtk_hbox_new ( no, 2 ) ;
	
	gtk_box_pack_start ( dialog -> vbox, l, no, no, 5 ) ;
	
	gtk_box_pack_start ( dialog -> vbox, gtk_hseparator_new (), no, no, 5 ) ;
	gtk_box_pack_start ( dialog -> vbox, sw, yes, yes, 2 ) ;
	
	gtk_box_pack_start ( dialog -> vbox, gtk_hseparator_new (), no, no, 5 ) ;
	
	gtk_box_pack_start ( dialog -> vbox, entry, no, no, 5 ) ;
	gtk_box_pack_start ( dialog -> vbox, box, no, no, 5 ) ;
	
	gtk_tree_view_set_headers_visible ( view, no ) ;
	gtk_container_add ( sw, view ) ;
	
	gtk_box_pack_start ( box, always, no, no, 2 ) ;
	gtk_box_pack_start ( box, terminal, no, no, 2 ) ;
	
	gtk_window_resize ( dialog, 320, 450 ) ;
	
	gtk_widget_show_all ( dialog ) ;
	if ( ! gtk_dialog_run ( dialog ))
	{
		gtk_widget_destroy ( dialog ) ;
		return ;
	}
	
	gchar * app = null, * app1 = gtk_entry_get_text ( entry ) ;
	if ( gtk_entry_get_text_length ( entry ))
		app = g_strdup ( app1 ) ;
	
	else
	{
		GtkTreeSelection * selection = gtk_tree_view_get_selection ( view ) ;
		GtkTreeIter iter ;
		
		if ( gtk_tree_selection_get_selected ( selection, null, & iter ))
		{
			gtk_tree_model_get ( store, & iter, 1, & app, -1 ) ;
		}
	}
	
	if ( app == null )
	{
		gtk_widget_destroy ( dialog ) ;
		return ;
	}
	
	GString * s = null ;
	
	if ( gtk_toggle_button_get_active ( terminal ))
	{
		s = g_string_new ( "xterm;-e;" ) ;
		g_string_append_printf ( s, app ) ;
	}
	
	else
		s = g_string_new ( app ) ;
	
	
	if ( gtk_toggle_button_get_active ( always ))
	{
		gchar * db = g_build_filename ( g_get_home_dir (), ".system", "mime.db", null ) ;
		april_key_file_set_string ( db, g_strrstr ( icon -> path, "." ), "exec", app ) ;
		
		g_free ( db ) ;
	}
	
	g_string_append_printf ( s, ";%s", icon -> path ) ;
	
	gchar ** vector = g_strsplit ( s -> str, ";", -1 ) ;
	GError * error = null ;
	
	g_spawn_async ( null, vector, null, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
					null, null, null, & error ) ;
	
	if ( error )
		g_warning ( error -> message ) ;
	
	g_string_free ( s, true ) ;
	g_strfreev ( vector ) ;
	
	g_free ( app ) ;
	gtk_widget_destroy ( dialog ) ;
	
}

vodi desktop_toggle_icons ( GtkWidget * widget, Desktop * desktop )
{
	gint i = 0, len = gtk_tree_model_iter_n_children ( desktop -> store, null ) ;
	desktop -> icons_visible = gtk_check_menu_item_get_active ( widget ) ;
	
	for ( i = 0 ; i < len ; i ++ )
	{
		GtkTreeIter iter ;
		gtk_tree_model_iter_nth_child ( desktop -> store, & iter, null, i ) ;
		
		GtkWidget * icon = null ;
		gtk_tree_model_get ( desktop -> store, & iter, 3, & icon, -1 ) ;
		
		if ( gtk_check_menu_item_get_active ( widget ))
			gtk_widget_show ( icon ) ;
		else
			gtk_widget_hide ( icon ) ;
		
		//april_update_gui () ;
		//g_usleep ( 50000 ) ;
	}
}

void desktop_refresh ( vodi )
{
	XFlush ( gdk_x11_get_default_xdisplay ()) ;
	
	/** This is how real X11 developers do it **/
	GtkWindow * w = gtk_window_new ( GTK_WINDOW_TOPLEVEL ) ;
	gtk_window_resize ( w, gdk_screen_width (), gdk_screen_height ()) ;
	
	gtk_window_fullscreen ( w ) ;
	gtk_window_set_decorated ( w, no ) ;
	
	GdkColor color ;
	color.red = color.green = color.blue = 0 ;
	
	gtk_widget_modify_bg ( w, GTK_STATE_NORMAL, & color ) ;
	gtk_widget_show ( w ) ;
	
	april_update_gui () ;
	g_usleep ( 10000 ) ;
	
	gtk_widget_destroy ( w ) ;
}

void desktop_changed ( GFileMonitor * fm, GFile * f1, GFile * f2, GFileMonitorEvent event, Desktop * d )
{
	g_debug ( "The desktop has changed. Event is %d ...", event ) ;
	
	switch ( event )
	{
		case G_FILE_MONITOR_EVENT_CREATED:
		{	
			gchar * full_name = g_file_get_path ( f1 ) ;
			g_debug ( full_name ) ;
			GdkPixbuf * p = fm_get_icon ( full_name ) ;
			
			GtkVBox * icon = gtk_vbox_new ( no, 2 ) ;
			GtkImage * image = gtk_image_new_from_pixbuf ( p ) ;
			
			gchar * name = g_file_get_basename ( f1 ) ;
			gchar * display_name = _desktop_icon_name_mod ( name ) ;
			
			GtkLabel * label = gtk_label_new ( null ) ;
			gchar * markup = g_markup_printf_escaped ( "<span color=\"white\">%s</span>", display_name ) ;
			
			g_free ( display_name ) ;
			
			gtk_label_set_markup ( label, markup ) ;
			g_free ( markup ) ;
			
			gtk_label_set_line_wrap ( label, true ) ;
			gtk_label_set_justify ( label, GTK_JUSTIFY_CENTER ) ;
			
			gtk_box_pack_start ( icon, image, no, no, 0 ) ;
			gtk_box_pack_start ( icon, label, no, no, 2 ) ;
			
			gtk_widget_set_tooltip_text ( icon, name ) ;
			
			GtkTreeIter iter ;
			gtk_list_store_append ( d -> store, & iter ) ;
			
			GtkEventBox * e = gtk_event_box_new () ;
			gtk_container_add ( e, icon ) ;
			
			DesktopIcon * c = desktop_icon_new ( d ) ;
			c -> store = d -> store ;
			
			c -> e = e ;
			c -> image = image ;
			
			c -> label = label ;
			c -> path = full_name ;
			
			c -> iter = gtk_tree_iter_copy ( & iter ) ;
			
			gint x = d -> icons_x ;
			gint y = d -> icons_y ;
			
			d -> icons_y = y = y + 100 ;
			
			if ( y > gdk_screen_height () - 60 )
			{
				x = d -> icons_x = 50 ;
				y = d -> icons_y = 0 ;
			}
			
			c -> x = x ;
			c -> y = y ;
			
			g_signal_connect_swapped ( e, "enter-notify-event", _desktop_icon_pointer_change, c ) ;
			g_signal_connect_swapped ( e, "leave-notify-event", _desktop_icon_pointer_reset, c ) ;
	
			g_signal_connect ( e, "button-press-event", desktop_icon_activated, c ) ;
			gtk_layout_put ( d -> lt, e, x, y ) ;
			
			gtk_list_store_set ( d -> store, & iter, 0, p, 1, name, 2, full_name, 3, e, 4, c, -1 ) ;
			gtk_event_box_set_visible_window ( e, no ) ;
			
			gtk_widget_show_all ( e ) ;
			g_free ( name ) ;
			
			g_object_unref ( p ) ;
			break ;
		}
	
		case G_FILE_MONITOR_EVENT_DELETED:
		{
			gint i = 0, len = gtk_tree_model_iter_n_children ( d -> store, null ) ;
			gchar * path1 = g_file_get_path ( f1 ) ;
			
			g_debug ( path1 ) ;
			for ( i = 0 ; i < len ; i ++ )
			{
				GtkTreeIter iter ;
				gtk_tree_model_iter_nth_child ( d -> store, & iter, null, i ) ;
				
				gchar * path2 = null ;
				gtk_tree_model_get ( d -> store, & iter, 2, & path2, -1 ) ;
				
				if ( g_strcmp0 ( path1, path2 ) == 0 )
				{
					DesktopIcon * icon ;
					gtk_tree_model_get ( d -> store, & iter, 4, & icon, -1 ) ;
					
					desktop_icon_destroy ( icon ) ;
					
					gtk_list_store_remove ( d -> store, & iter ) ;
				}
				
				g_free ( path2 ) ;
			}
			
			g_free ( path1 ) ;
			break ;
		}

		default:
			break ;
	}
}

void desktop_arrange_icons ( Desktop * d )
{
	gint i = 0, len = gtk_tree_model_iter_n_children ( d -> store, null ) ;
	gint x = 50, y = 0 ;
	
	for ( i = 0 ; i < len ; i ++ )
	{
		GtkTreeIter iter ;
		gtk_tree_model_iter_nth_child ( d -> store, & iter, null, i ) ;
		
		GtkWidget * e = null ;
		gtk_tree_model_get ( d -> store, & iter, 3, & e, -1 ) ;
		
		gtk_layout_move ( d -> lt, e, x, y ) ;
		
		d -> icons_x = x ;
		d -> icons_y = y ;
		
		y = y + 100 ;
		
		if ( y > gdk_screen_height () - 60 )
		{
			y = 0 ;
			x = x + 100 ;
		}
		
	}
}

void desktop_line_up_icons ( Desktop * d )
{
	gint i = 0, len = gtk_tree_model_iter_n_children ( d -> store, null ) ;
	gint x = 50, y = 0 ;
	
	for ( i = 0 ; i < len ; i ++ )
	{
		GtkTreeIter iter ;
		gtk_tree_model_iter_nth_child ( d -> store, & iter, null, i ) ;
		
		GtkWidget * e = null ;
		gtk_tree_model_get ( d -> store, & iter, 3, & e, -1 ) ;
		
		gtk_layout_move ( d -> lt, e, x, y ) ;
		
		d -> icons_x = x ;
		d -> icons_y = y ;
		
		x = x + 100 ;
		
		if ( x > gdk_screen_width () - 60 )
		{
			x = 0 ;
			y = y + 100 ;
		}
		
	}
}

void desktop_paste_from_clipboard ( Desktop * d )
{
	g_debug ( "Attempting to paste ..." ) ;
	gtk_clipboard_request_text ( gtk_clipboard_get ( GDK_NONE ), desktop_paste_from_clipboard_callback, d ) ;
}

void desktop_paste_from_clipboard_callback ( GtkClipboard * clipboard, gchar * text, Desktop * d )
{
	if ( text == null )
		return ;
	
	gchar ** vector = g_strsplit ( text, ";", -1 ) ;
	ClipboardAction action = atoi ( vector [0] ) ;
	
	g_debug ( "Action is %d", action ) ;
	switch ( action )
	{
		case CUT:
		case COPY:
		case PASTE:
			gtk_true () ;
			break ;
		default:
			g_critical ( "Unable to perform operation ! "
						 "Invalid clipboard action specified." ) ;
			
			g_strfreev ( vector ) ;
			return ;
	}

	if ( vector [1] == null )
	{
		g_message ( "No files to paste !" ) ;
		g_strfreev ( vector ) ;
		
		return ;
	}
	
	GList * list = null ;
	
	gint i = 1 ;
	while ( vector [i] != null )
	{
		list = g_list_append ( list, vector [i] ) ;
		
		g_debug ( "Files to paste: [%d] %s", i, vector [i] ) ;
		i ++ ;
	}
	
	gchar * path = g_file_get_path ( d -> desktop ) ;
	xfer_xfer ( null, action, list, path ) ;
	
	//g_list_foreach ( list, g_free, null ) ;
	g_strfreev ( vector ) ;
	g_list_free ( list ) ;
	
	g_free ( path ) ;
}

void _desktop_paste_shortcut ( GtkClipboard * clipboard, gchar * text, Desktop * d )
{
	if ( text == null )
		return ;
	
	gchar ** vector = g_strsplit ( text, ";", -1 ) ;
	if ( vector [1] == null )
	{
		g_message ( "No files to paste !" ) ;
		g_strfreev ( vector ) ;
		
		return ;
	}
	
	gint i = 1 ;
	while ( vector [i] != null )
	{
		gchar * path = vector [i] ;
		gchar * dirname = g_file_get_path ( d -> desktop ) ;
		
		gchar * basename = g_path_get_basename ( path ) ;
		gchar * new_link = g_strdup_printf ( "%s/Link to %s", dirname, basename ) ;
	
		g_debug ( "Creating shortcut %s", new_link ) ;

		if ( symlink ( path, new_link ))
			g_warning ( "Cannot create shortcut for %s: %s", 
						path, strerror ( errno )) ;
		
		g_free ( new_link ) ;
		g_free ( dirname ) ;
		
		g_free ( basename ) ;
		i ++ ;
	}
	
	g_strfreev ( vector ) ;
}

void desktop_paste_shortcut ( Desktop * d )
{
	g_debug ( "Attempting to paste shortcut ..." ) ;
	gtk_clipboard_request_text ( gtk_clipboard_get ( GDK_NONE ), _desktop_paste_shortcut, d ) ;
}

void desktop_delete_from_clipboard_callback ( GtkClipboard * clipboard, gchar * text, Desktop * d )
{
	if ( text == null )
		return ;
	
	gchar ** vector = g_strsplit ( text, ";", -1 ) ;
	if ( vector [1] == null )
	{
		g_message ( "No files to delete !" ) ;
		g_strfreev ( vector ) ;
		
		return ;
	}
	
	GList * list = null ;
	
	gint i = 1 ;
	while ( vector [i] != null )
	{
		gchar * basename = g_path_get_basename ( vector [i] ) ;
		gchar * parent = g_file_get_path ( d -> desktop ) ;
		
		gchar * path = g_build_filename ( parent, basename, null ) ;
		list = g_list_append ( list, path ) ;
		
		g_free ( basename ) ;
		g_free ( parent ) ;
		
		g_debug ( "Files to delete: [%d] %s", i, path ) ;
		i ++ ;
	}
	
	xfer_delete ( null, list ) ;
	g_list_foreach ( list, g_free, null ) ;

	g_strfreev ( vector ) ;
	g_list_free ( list ) ;
	
}

void desktop_delete_from_clipboard ( Desktop * d )
{
	g_debug ( "Attempting to delete ..." ) ;
	gtk_clipboard_request_text ( gtk_clipboard_get ( GDK_NONE ), desktop_delete_from_clipboard_callback, d ) ;
}

void desktop_new_folder ( Desktop * d )
{
	gchar * name = prompt_get_string ( "New folder", "Type the name of new folder" ) ;
	if ( name == null )
		return ;
	
	gchar * parent = g_file_get_path ( d -> desktop ) ;
	gchar * filename = g_build_filename ( parent, name, null ) ;
	
	if ( g_mkdir_with_parents ( filename, 0700 ))
		g_critical ( "Cannot create folder: %s", strerror ( errno )) ;
	
	g_free ( parent ) ;
	g_free ( filename ) ;
	
	g_free ( name ) ;
}

void desktop_new_file ( Desktop * d )
{
	gchar * name = prompt_get_string ( "Empty file", "Type the name of new empty file" ) ;
	if ( name == null )
		return ;
	
	gchar * parent = g_file_get_path ( d -> desktop ) ;
	gchar * filename = g_build_filename ( parent, name, null ) ;
	
	File * fp = fopen ( filename, "w" ) ;
	if ( fp == null )
		g_critical ( "Cannot create file: %s", strerror ( errno )) ;
	else
	{
		fclose ( fp ) ;
	}
	
	g_free ( parent ) ;
	g_free ( filename ) ;
	
	g_free ( name ) ;
}

void _desktop_icon_pointer_change ( DesktopIcon * icon )
{
	gdk_window_set_cursor ( gtk_widget_get_parent_window ( icon -> e ), icon -> desktop -> hand ) ;
}

void _desktop_icon_pointer_reset ( DesktopIcon * icon )
{
	gdk_window_set_cursor ( gtk_widget_get_parent_window ( icon -> e ), icon -> desktop -> ptr ) ;
}

vodi desktop_get_wallpapers ( GtkListStore * store )
{
	GtkTreeIter iter ;
	gtk_list_store_append ( store, & iter ) ;
	
	GdkPixbuf * pixbuf = gtk_icon_theme_load_icon ( gtk_icon_theme_get_default (),
													"gtk-cancel",
													128,
													GTK_ICON_LOOKUP_USE_BUILTIN | GTK_ICON_LOOKUP_FORCE_SIZE,
													null ) ;
	gtk_list_store_set ( store, & iter, 0, "None", 1, null, 2, pixbuf, -1 ) ;
	
	g_object_unref ( pixbuf ) ;
	
	GDir * dir = g_dir_open ( "/usr/share/wallpapers", 0, null ) ;
	if ( dir == null )
	{
		g_warning ( "Cannot open wallpaper folder !" ) ;
		return ;
	}
	
	gchar * name = g_dir_read_name ( dir ) ;
	while ( name )
	{
		gchar * full_name = g_build_filename ( "/usr/share/wallpapers", name, null ) ;
		GdkPixbuf * pixbuf = gdk_pixbuf_new_from_file_at_scale ( full_name, 128, 128, true, null ) ;
		
		if ( pixbuf )
		{
			GtkTreeIter iter ;
			gtk_list_store_append ( store, & iter ) ;
			
			gtk_list_store_set ( store, & iter, 0, name, 1, full_name, 2, pixbuf, -1 ) ;
			g_object_unref ( pixbuf ) ;
		}
		
		g_free ( full_name ) ;
		name = g_dir_read_name ( dir ) ;
		
	}
	
	g_dir_close ( dir ) ; 
}


void desktop_properties ( Desktop * d )
{
	GtkDialog * dialog = gtk_dialog_new_with_buttons ( "Desktop properties",
														d -> window,
														GTK_DIALOG_MODAL,
														"Ok",
														1,
														null ) ;
	
	GtkListStore * store = gtk_list_store_new ( 3, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_PIXBUF ) ;
	GtkIconView * view = gtk_icon_view_new_with_model ( store ) ;
	
	//gtk_icon_view_set_text_column ( view, 0 ) ;
	gtk_icon_view_set_pixbuf_column ( view, 2 ) ;
	
	gtk_icon_view_set_orientation ( view, GTK_ORIENTATION_HORIZONTAL ) ;
	g_signal_connect ( view, "item-activated", _desktop_wallpaper_change, d ) ;
	
	gtk_icon_view_set_tooltip_column ( view, 1 ) ;
	
	GtkScrolledWindow * sw = gtk_scrolled_window_new ( null, null ) ;
	gtk_container_add ( sw, view ) ;
	
	GtkNotebook * notebook = gtk_notebook_new () ;
	gtk_box_pack_start ( dialog -> vbox, notebook, yes, yes, 5 ) ;
	
	gtk_notebook_append_page ( notebook, sw, gtk_label_new ( "Wallpaper" )) ;
	gtk_scrolled_window_set_policy ( sw, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ) ;
	
	gtk_window_resize ( dialog, 450, 350 ) ;
	gtk_widget_show_all ( dialog ) ;

	april_update_gui () ;
	gdk_window_set_cursor ( gtk_widget_get_parent_window ( view ), d -> busy ) ;
	
	april_update_gui () ;
	desktop_get_wallpapers ( store ) ;
	
	gdk_window_set_cursor ( gtk_widget_get_parent_window ( view ), d -> ptr ) ;
	
	gtk_dialog_run ( dialog ) ;
	gtk_widget_destroy ( dialog ) ;
}
	
void _desktop_wallpaper_change ( GtkIconView * view, GtkTreePath * path, Desktop * d )
{
	GtkTreeModel * model = gtk_icon_view_get_model ( view ) ;
	GtkTreeIter iter ;

	gtk_tree_model_get_iter ( model, & iter, path ) ;
	
	gchar * filename = null ;
	gtk_tree_model_get ( model, & iter, 1, & filename, -1 ) ;
	
	gtk_image_set_from_file ( d -> wallpaper, filename ) ;
	g_free ( filename ) ;
}
